package SSF.OS.OSPFv2.test;

/**
  * Reset.java
  *
  * @author Dirk Jacob
  * @version 0.2.1
  */

import java.util.*;
import com.renesys.raceway.DML.*;

/** Implements a pseudo-protocol, which restarts an OSPF router at given
  * times. The protocol can be configured as follows:
  * <pre>
  *   ProtocolSession[ name reset use SSF.OS.OSPF.test.Reset
  *       stop  10.0
  *       start 20.0
  *       stop  30.0
  *       start 40.0
  *       ...
  *   ]
  * </pre>
  */
public class Reset extends ProtocolSession {
	
	/** Reference to the associated OSPF Session. This field is set in the 
	  * <code>init()</code> method. */
	private ProtocolSession ospfSession;
	/** Stores all the timers used for starting and stopping OSPF. */
	private Vector timers;
	/** Stores the timer events from the configuration for later initialization
	    of timers. */
	private Vector timerConfig;
	/** Logger for this class. */
	private Logger log = null;
	
	/** Indicates, that the OSPF session should be stopped. */
	private static final int STOP  = 0x01;
	/** Indicates, that the OSPF session should be started. */
	private static final int START = 0x02;
	
	/** Holds the configuration of a single timer. */
	class TimerConfiguration {
		/** START or STOP */
		private int action;
		/** time */
		private long expires;
		
		/** Constructor */
		public TimerConfiguration(long exp, int act) {
			action = act;
			expires = exp;
		}
		
		/** Determine, when this timer expires */
		public long getDuration() {
			
			return expires;
		}
		
		/** Determine the action of this timer */
		public int getAction() {
			
			return action;
		}
	}
	
	/** Stops and starts an OSPF session.
	  */
	class ResetTimer extends SSF.OS.Timer{
		
		/** START or STOP */
		private int action;
		/** When does this timer expire */
		private long expires;
		
		/** Constructs a ResetTimer.
		  * @param e The protocol graph this timer belongs to.
		  * @param dt Time period.
		  * @param act Determines if this timer describes a START or a STOP event.
		  */
		public ResetTimer(ProtocolGraph e, long dt, int act) {
			
			super(e, dt);
			
			action = act;
			expires = dt;
		}
		
		/** Constructs a ResetTimer.
		  * @param e The protocol graph this timer belongs to.
		  * @param cfg Timer configuration.
		  */
		public ResetTimer(ProtocolGraph e, TimerConfiguration cfg) {
			
			this( e, cfg.getDuration(), cfg.getAction() );
		}
		
		/** Starts this timer */
		public void start() {
			
			this.set( expires );
		}
		

		/** Callback method, which calls the central event dispatcher. */
		public void callback() {
			try {
				if( action == START ) {
					log.logMessage("(Re-)Starting OSPF session.");
					((OSPF)ospfSession).init();
				} else if( action == STOP ) {
					log.logMessage("Shutting down OSPF session.");
					((OSPF)ospfSession).stop();
				} else {
					log.logMessage("WARNING: Unknown action event. Ignored.");
				}
			} catch (ProtocolException e) {
				log.logMessage("ERROR: (Re-)Start of OSPF failed (ProtocolException in OSPF.init()).");
			} catch (Exception e) {
				log.logMessage("EXCEPTION: "+ e.getMessage());
				e.printStackTrace();
			}
		}
	}
	
	/** Standard constructor. */
	public Reset() {
	
		ospfSession = null;
		timers = new Vector();
		timerConfig = new Vector();
		log = new Logger(Logger.DEBUG_ALL, this, "Reset");
	}
	
	/** Configure this protocol session. 
	  * @param cfg DML configuration for this protocol session.
	  * @exception com.renesys.raceway.DML.configException
	  */
	public void config(Configuration cfg) throws configException {
		
		/* Read all stop events and store their configuration in the timerConfig vector */
		for(Enumeration stops = cfg.find("stop"); stops.hasMoreElements();) {
			
			double time = Double.parseDouble((String)stops.nextElement());
			
			TimerConfiguration c = new TimerConfiguration(SSF.Net.Net.seconds(time), STOP);
			timerConfig.add( c );
		}
		
		/* Read all start events and store their configuration in the timerConfig vector */
		for(Enumeration stops = cfg.find("start"); stops.hasMoreElements();) {
			
			String tstr = (String)stops.nextElement();
			double time = Double.parseDouble( tstr );
			
			TimerConfiguration c = new TimerConfiguration(SSF.Net.Net.seconds(time), START);
			timerConfig.add( c );
		}
		
		super.config(cfg);
	}
	
	/** Initialize this protocol session. All the timers are started here.
	  * @exception SSF.OS.ProtocolException
	  */
	public void init() throws ProtocolException {
			
		ospfSession = inGraph().SessionForName("ospf");
		
		/* now build and start all the timers */
		for(Enumeration e = timerConfig.elements(); e.hasMoreElements(); ) {
			TimerConfiguration c = (TimerConfiguration)e.nextElement();
			
			ResetTimer t = new ResetTimer( inGraph(), c );
			timers.add( t );
			t.start();
		}
	}
	
	/** Is called by other protocols for the exchange of protocol messages. Must not be called,
	  * because this protocol session does not handle any messages. 
	  * @exception SSF.OS.ProtocolException
	  */
	public boolean push(ProtocolMessage message, ProtocolSession fromSession) throws ProtocolException{
	
		/* this method should never be called - the protocol is not expected to
		   handle incoming packets! */
		throw new ProtocolException("Method push in SSF.OS.OSPF.test.Reset must not be called!");
    }
}  